package com.gps.pe.utility;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.KeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;

import com.gps.pe.exception.PeSecurityException;

/**
 * Utility file for String operations
 * 
 * @author GPS
 *
 */
public final class StringUtils {
	/**
	 * Method return true if string is empty or null
	 * 
	 * @param str
	 * @return
	 */
	public static boolean isStringEmpty(final String str) {
		return ((str == null || str.length() == 0) ? true : false);
	}

	/**
	 * Method to encrypt any string based on SEED (string type secretKey)
	 * 
	 * @param secretKey
	 * @param plainText
	 *            - Encrypt plain text
	 * @return String
	 * @throws PeSecurityException
	 * 
	 */
	public static String encryptString(String secretKey, String plainText) throws PeSecurityException {
		String encStr = plainText;
		try {
			Cipher ecipher;

			byte[] salt = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3,
					(byte) 0x03 };

			int iterationCount = 19;

			KeySpec keySpec = new PBEKeySpec(secretKey.toCharArray(), salt, iterationCount);
			SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);

			AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

			ecipher = Cipher.getInstance(key.getAlgorithm());
			ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
			String charSet = "UTF-8";
			byte[] in = plainText.getBytes(charSet);
			byte[] out = ecipher.doFinal(in);
			encStr = new sun.misc.BASE64Encoder().encode(out);
		} catch (NullPointerException | NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException
				| InvalidAlgorithmParameterException | UnsupportedEncodingException | IllegalBlockSizeException
				| BadPaddingException e) {
			throw new PeSecurityException("Problem to encrypt [" + plainText + "] string...", e);
		}
		return encStr;
	}

	/**
	 * Method to decrypt any string based on SEED(string type secretKey)
	 * 
	 * @param secretKey
	 * @param encryptedText
	 * @return String
	 * @throws PeSecurityException
	 */
	public static String decryptString(String secretKey, String encryptedText) throws PeSecurityException {
		String plainStr = encryptedText;
		try {
			Cipher dcipher;

			byte[] salt = { (byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x35, (byte) 0xE3,
					(byte) 0x03 };

			int iterationCount = 19;

			KeySpec keySpec = new PBEKeySpec(secretKey.toCharArray(), salt, iterationCount);
			SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);

			AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

			dcipher = Cipher.getInstance(key.getAlgorithm());
			dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);
			byte[] enc = new sun.misc.BASE64Decoder().decodeBuffer(encryptedText);
			byte[] utf8 = dcipher.doFinal(enc);
			String charSet = "UTF-8";
			plainStr = new String(utf8, charSet);
		} catch (NullPointerException | NoSuchAlgorithmException | InvalidKeySpecException | NoSuchPaddingException | InvalidKeyException
				| InvalidAlgorithmParameterException | IllegalBlockSizeException | BadPaddingException | IOException e) {
			throw new PeSecurityException("Problem to decrypt [" + encryptedText + "] string...", e);
		}
		return plainStr;
	}

	private StringUtils() {
		// Utility class, hide constructor.
	}
}
